package org.hfy.utils;

import lombok.extern.slf4j.Slf4j;
import org.hfy.entity.Contract;
import org.hfy.entity.Customer;
import org.hfy.entity.Employee;
import org.hfy.entity.Quotation;
import org.hfy.entity.QuotationItem;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

/**
 * 合同HTML模板处理工具类
 * 
 * @author hfy
 * @version 1.0
 */
@Slf4j
public class ContractHtmlTemplateProcessor {

    private static final String TEMPLATE_PATH = "/templates/contract_temp_new.html";
    
    /**
     * 使用HTML模板生成合同
     * 
     * @param contract 合同对象
     * @return HTML内容字符串
     */
    public static String generateContractFromTemplate(Contract contract) {
        return generateContractFromTemplate(contract, null, null);
    }
    
    /**
     * 使用HTML模板生成合同（带客户和员工信息）
     * 
     * @param contract 合同对象
     * @param customer 客户信息
     * @param employee 员工信息
     * @return HTML内容字符串
     */
    public static String generateContractFromTemplate(Contract contract, Customer customer, Employee employee) {
        try (InputStream templateStream = ContractHtmlTemplateProcessor.class.getResourceAsStream(TEMPLATE_PATH)) {
            
            if (templateStream == null) {
                log.error("合同HTML模板文件不存在: {}", TEMPLATE_PATH);
                throw new RuntimeException("合同HTML模板文件不存在");
            }
            
            // 读取模板内容
            String templateContent = readTemplateContent(templateStream);
            
            // 构建替换数据
            Map<String, String> replacements = buildReplacementData(contract, customer, employee);
            
            // 替换占位符
            String htmlContent = replaceTemplateVariables(templateContent, replacements);
            
            // 处理物料详情
            if (contract.getQuotation() != null && contract.getQuotation().getItems() != null) {
                String itemRows = generateItemRows(contract.getQuotation().getItems());
                htmlContent = htmlContent.replace("${物料详情行}", itemRows);
            } else {
                htmlContent = htmlContent.replace("${物料详情行}", generateEmptyItemRow());
            }
            
            // 处理图片路径，将图片转换为Base64编码
            htmlContent = processImagePaths(htmlContent);
            
            return htmlContent;
            
        } catch (Exception e) {
            log.error("使用HTML模板生成合同失败: {}", e.getMessage(), e);
            throw new RuntimeException("生成合同HTML失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 读取模板文件内容
     * 
     * @param inputStream 输入流
     * @return 模板内容
     */
    private static String readTemplateContent(InputStream inputStream) {
        try (Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name())) {
            scanner.useDelimiter("\\A");
            return scanner.hasNext() ? scanner.next() : "";
        }
    }
    
    /**
     * 构建替换数据映射
     * 
     * @param contract 合同对象
     * @return 替换数据映射
     */
    private static Map<String, String> buildReplacementData(Contract contract) {
        return buildReplacementData(contract, null, null);
    }
    
    /**
     * 构建替换数据映射（带客户和员工信息）
     * 
     * @param contract 合同对象
     * @param customer 客户信息
     * @param employee 员工信息
     * @return 替换数据映射
     */
    private static Map<String, String> buildReplacementData(Contract contract, Customer customer, Employee employee) {
        Map<String, String> replacements = new HashMap<>();
        
        // 合同基础信息
        replacements.put("${合同编号}", getDisplayValue(contract.getContractNo()));
        String status = getDisplayValue(contract.getStatus());
        replacements.put("${审核状态}", status.isEmpty() ? "待审核" : status);
        replacements.put("${审核人}", getDisplayValue(contract.getAuditBy()));
        replacements.put("${创建时间}", contract.getCreatedAt() != null ? 
            contract.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) : "");
        replacements.put("${审核时间}", contract.getAuditTime() != null ? 
            contract.getAuditTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : "");
        replacements.put("${审核备注}", getDisplayValue(contract.getAuditRemark()));
        
        // 报价单相关信息
        if (contract.getQuotation() != null) {
            Quotation quotation = contract.getQuotation();
            
            replacements.put("${报价单号}", getDisplayValue(quotation.getQuotationNo()));
            replacements.put("${客户代码}", getDisplayValue(quotation.getCustomerCode()));
            replacements.put("${客户名称}", getDisplayValue(quotation.getCustomerName()));
            replacements.put("${业务员}", getDisplayValue(quotation.getSalesperson()));
            replacements.put("${合同金额}", quotation.getTotalAmount() != null ? 
                formatAmount(quotation.getTotalAmount()) : "0.00");
            replacements.put("${合同金额大写}", quotation.getTotalAmount() != null ? 
                convertAmountToChinese(quotation.getTotalAmount()) : "零元整");
            replacements.put("${付款方式}", getDisplayValue(quotation.getPaymentMethod()));
            replacements.put("${是否含税}", quotation.getIsTaxIncluded() != null && quotation.getIsTaxIncluded() ? 
                "■ 增值税票13%" : "□ 增值税票13%");
            replacements.put("${备注}", getDisplayValue(quotation.getRemark()));
            
            // 新增变量：业务员电话
            replacements.put("${业务员电话}", employee != null ? getDisplayValue(employee.getPhone()) : "");
        } else {
            // 空值处理
            replacements.put("${报价单号}", "");
            replacements.put("${客户代码}", "");
            replacements.put("${客户名称}", "");
            replacements.put("${业务员}", "");
            replacements.put("${合同金额}", "0.00");
            replacements.put("${合同金额大写}", "零元整");
            replacements.put("${付款方式}", "");
            replacements.put("${是否含税}", "□ 增值税票13%");
            replacements.put("${备注}", "");
            replacements.put("${业务员电话}", "");
        }
        
        // 新增变量：客户信息
        if (customer != null) {
            replacements.put("${客户联系电话}", getDisplayValue(customer.getContactPhone()));
            replacements.put("${客户联系地址}", getDisplayValue(customer.getCompanyAddress()));
            replacements.put("${甲方单位地址}", getDisplayValue(customer.getCompanyAddress()));
        } else {
            replacements.put("${客户联系电话}", "");
            replacements.put("${客户联系地址}", "");
            replacements.put("${甲方单位地址}", "");
        }
        
        // 当前日期
        replacements.put("${当前日期}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        
        return replacements;
    }
    
    /**
     * 替换模板中的占位符变量
     * 
     * @param templateContent 模板内容
     * @param replacements 替换数据映射
     * @return 替换后的内容
     */
    private static String replaceTemplateVariables(String templateContent, Map<String, String> replacements) {
        String result = templateContent;
        
        for (Map.Entry<String, String> entry : replacements.entrySet()) {
            result = result.replace(entry.getKey(), entry.getValue());
        }
        
        return result;
    }
    
    /**
     * 生成物料详情行
     * 
     * @param items 物料详情列表
     * @return HTML行内容
     */
    private static String generateItemRows(List<QuotationItem> items) {
        StringBuilder rows = new StringBuilder();
        
        for (int i = 0; i < items.size(); i++) {
            QuotationItem item = items.get(i);
            rows.append(generateSingleItemRow(item, i + 1));
        }
        
        return rows.toString();
    }
    
    /**
     * 生成单个物料详情行
     * 
     * @param item 物料详情
     * @param itemNo 序号
     * @return HTML行内容
     */
    private static String generateSingleItemRow(QuotationItem item, int itemNo) {
        StringBuilder row = new StringBuilder();
        row.append("<tr>");
        
        // 序号
        row.append("<td>").append(itemNo).append("</td>");
        
        // 产品名称
        row.append("<td>").append(getDisplayValue(item.getProductName())).append("</td>");
        
        // 物料编码 (第二行第一个单元格)
        row.append("<td>").append(getDisplayValue(item.getMaterialCode())).append("</td>");
        
        // 层数 (新增字段，暂时使用固定值)
        row.append("<td>").append(getDisplayValue(item.getLayers() != null ? item.getLayers() : "2")).append("</td>");
        
        // 板材 
        row.append("<td>").append(getDisplayValue(item.getBoardMaterial() != null ? item.getBoardMaterial() : "FR-4")).append("</td>");
        
        // 板厚
        row.append("<td>").append(getDisplayValue(item.getThickness())).append("</td>");
        
        // 内铜 (调整顺序)
        row.append("<td>").append(getDisplayValue(item.getInnerCopper())).append("</td>");
        
        // 外铜 (调整顺序)
        row.append("<td>").append(getDisplayValue(item.getOuterCopper())).append("</td>");
        
        // 交货尺寸
        row.append("<td>").append(getDisplayValue(item.getDeliverySize())).append("</td>");
        
        // 拼板
        row.append("<td>").append(getDisplayValue(item.getPanelization())).append("</td>");
        
        // 表面处理
        row.append("<td>").append(getDisplayValue(item.getSurfaceTreatment())).append("</td>");
        
        // 阻焊
        row.append("<td>").append(getDisplayValue(item.getSolderMask())).append("</td>");
        
        // 字符
        row.append("<td>").append(getDisplayValue(item.getCharacter())).append("</td>");
        
        // 过孔工艺
        row.append("<td>").append(getDisplayValue(item.getViaProcess())).append("</td>");
        
        // 测试
        row.append("<td>").append(getDisplayValue(item.getTesting())).append("</td>");
        
        // 数量PCS
        row.append("<td>").append(item.getQuantity() != null ? item.getQuantity().toString() : "0").append("</td>");
        
        // 单价
        row.append("<td>").append(item.getUnitPrice() != null ? formatAmount(item.getUnitPrice()) : "0.00").append("</td>");
        
        // 板费 (新名称，原测试架费)
        row.append("<td>").append(item.getTestingFee() != null ? formatAmount(item.getTestingFee()) : "0.00").append("</td>");
        
        // 工程费
        row.append("<td>").append(item.getCosts() != null && item.getCosts().getEngineeringFee() != null ? 
            formatAmount(item.getCosts().getEngineeringFee()) : "0.00").append("</td>");
        
        // 测试费 (新名称，原样板费)
        row.append("<td>").append(item.getSampleFee() != null ? formatAmount(item.getSampleFee()) : "0.00").append("</td>");
        
        // 其它 (新增字段)
        row.append("<td>").append(item.getOtherFee() != null ? formatAmount(item.getOtherFee()) : "0.00").append("</td>");
        
        // 合计金额
        row.append("<td>").append(item.getTotalAmount() != null ? formatAmount(item.getTotalAmount()) : "0.00").append("</td>");
        
        // 交期
        row.append("<td>").append(item.getDeliveryDate() != null ? 
            item.getDeliveryDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) : "").append("</td>");
        
        // 备注
        String remark = getDisplayValue(item.getItemRemark());
        if (remark.contains("\n")) {
            remark = remark.replace("\n", "<br>");
        }
        row.append("<td>").append(remark).append("</td>");
        
        row.append("</tr>");
        return row.toString();
    }
    
    /**
     * 生成空的物料详情行
     * 
     * @return HTML行内容
     */
    private static String generateEmptyItemRow() {
        StringBuilder row = new StringBuilder();
        row.append("<tr>");
        for (int i = 0; i < 23; i++) { // 更新列数：序号+产品名称+物料编码+层数+板材+板厚+内铜+外铜+交货尺寸+拼板+表面处理+阻焊+字符+过孔工艺+测试+数量PCS+单价+板费+工程费+测试费+其它+合计金额+交期+备注
            row.append("<td>-</td>");
        }
        row.append("</tr>");
        return row.toString();
    }
    
    /**
     * 获取显示值，如果值为"无"则返回空字符串
     * 
     * @param value 原始值
     * @return 处理后的显示值
     */
    private static String getDisplayValue(String value) {
        if (value == null || value.trim().isEmpty() || "无".equals(value.trim())) {
            return "";
        }
        return value;
    }
    
    /**
     * 获取显示值，处理Object类型的值
     * 
     * @param value 原始值
     * @return 处理后的显示值
     */
    private static String getDisplayValue(Object value) {
        if (value == null) {
            return "";
        }
        return getDisplayValue(value.toString());
    }
    
    /**
     * 格式化金额
     * 
     * @param amount 金额
     * @return 格式化后的金额字符串
     */
    private static String formatAmount(BigDecimal amount) {
        if (amount == null) {
            return "0.00";
        }
        return String.format("%.2f", amount.doubleValue());
    }
    
    /**
     * 将金额转换为中文大写
     * 
     * @param amount 金额
     * @return 中文大写金额
     */
    private static String convertAmountToChinese(BigDecimal amount) {
        if (amount == null || amount.compareTo(BigDecimal.ZERO) == 0) {
            return "零元整";
        }
        
        String[] units = {"", "拾", "佰", "仟", "万", "拾万", "佰万", "仟万", "亿"};
        String[] numbers = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
        
        // 简化实现，仅处理整数部分
        long yuan = amount.longValue();
        long jiao = ((amount.multiply(BigDecimal.valueOf(10)).longValue()) % 10);
        long fen = ((amount.multiply(BigDecimal.valueOf(100)).longValue()) % 10);
        
        if (yuan == 0 && jiao == 0 && fen == 0) {
            return "零元整";
        }
        
        StringBuilder result = new StringBuilder();
        String yuanStr = String.valueOf(yuan);
        
        // 处理元
        for (int i = 0; i < yuanStr.length(); i++) {
            int digit = Integer.parseInt(yuanStr.substring(i, i + 1));
            if (digit != 0) {
                result.append(numbers[digit]);
                int unitIndex = yuanStr.length() - i - 1;
                if (unitIndex < units.length) {
                    result.append(units[unitIndex]);
                }
            } else if (result.length() > 0 && !result.toString().endsWith("零")) {
                result.append("零");
            }
        }
        
        if (result.length() > 0) {
            result.append("元");
        } else {
            result.append("零元");
        }
        
        // 处理角分
        if (jiao != 0 || fen != 0) {
            if (jiao != 0) {
                result.append(numbers[(int)jiao]).append("角");
            }
            if (fen != 0) {
                result.append(numbers[(int)fen]).append("分");
            }
        } else {
            result.append("整");
        }
        
        return result.toString();
    }
    
    /**
     * 处理图片路径，将图片转换为Base64编码
     * 
     * @param htmlContent HTML内容
     * @return 处理后的HTML内容
     */
    private static String processImagePaths(String htmlContent) {
        try {
            // 处理logo图片
            String logoImageBase64 = loadImageAsBase64("/img/logo.png");
            if (logoImageBase64 != null) {
                // 替换logo图片src路径为Base64编码
                htmlContent = htmlContent.replace("../img/logo.png", "data:image/png;base64," + logoImageBase64);
                log.debug("Logo图片已转换为Base64编码");
            } else {
                log.warn("Logo图片加载失败，将保持原路径");
            }
            
            // 处理盖章图片
            String stampImageBase64 = loadImageAsBase64("/img/gaizhang.png");
            if (stampImageBase64 != null) {
                // 替换盖章图片src路径为Base64编码
                htmlContent = htmlContent.replace("../img/gaizhang.png", "data:image/png;base64," + stampImageBase64);
                log.debug("盖章图片已转换为Base64编码");
            } else {
                log.warn("盖章图片加载失败，将保持原路径");
            }
            
            log.info("图片路径处理完成，logo和盖章图片均已转换为Base64编码");
            return htmlContent;
            
        } catch (Exception e) {
            log.error("处理图片路径失败: {}", e.getMessage(), e);
            // 如果处理失败，返回原HTML内容
            return htmlContent;
        }
    }
    
    /**
     * 加载图片文件并转换为Base64编码
     * 
     * @param imagePath 图片路径（类路径相对路径）
     * @return Base64编码字符串，失败时返回null
     */
    private static String loadImageAsBase64(String imagePath) {
        try (InputStream imageStream = ContractHtmlTemplateProcessor.class.getResourceAsStream(imagePath)) {
            
            if (imageStream == null) {
                log.warn("图片文件不存在: {}", imagePath);
                return null;
            }
            
            // 读取图片文件字节（Java 8 兼容方式）
            byte[] imageBytes = readInputStreamToByteArray(imageStream);
            
            // 转换为Base64编码
            String base64Image = Base64.getEncoder().encodeToString(imageBytes);
            
            log.debug("成功加载图片: {}, 大小: {} bytes", imagePath, imageBytes.length);
            return base64Image;
            
        } catch (Exception e) {
            log.error("加载图片失败: {}, 错误: {}", imagePath, e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 将InputStream读取为字节数组（Java 8 兼容方法）
     * 
     * @param inputStream 输入流
     * @return 字节数组
     * @throws IOException IO异常
     */
    private static byte[] readInputStreamToByteArray(InputStream inputStream) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        byte[] data = new byte[1024];
        int bytesRead;
        
        while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, bytesRead);
        }
        
        return buffer.toByteArray();
    }
} 